package logic

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

// HLSService HLS流媒体服务
type HLSService struct {
	OutputDir       string
	SegmentDuration int
	MaxSegments     int
}

// NewHLSService 创建HLS服务实例
func NewHLSService() *HLSService {
	return &HLSService{
		OutputDir:       "./static/hls",
		SegmentDuration: 10, // 10秒一个片段
		MaxSegments:     0,  // 0表示保留所有片段
	}
}

// VideoInfo 视频信息
type VideoInfo struct {
	ID          string    `json:"id"`
	Title       string    `json:"title"`
	Duration    float64   `json:"duration"`
	Resolution  string    `json:"resolution"`
	Size        int64     `json:"size"`
	CreatedAt   time.Time `json:"created_at"`
	PlaylistURL string    `json:"playlist_url"`
	Status      string    `json:"status"` // processing, ready, error
}

// ConvertVideoToHLS 将视频转换为HLS格式
func (s *HLSService) ConvertVideoToHLS(inputPath, videoID string, options map[string]interface{}) error {
	// 创建输出目录
	outputDir := filepath.Join(s.OutputDir, videoID)
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %v", err)
	}

	// 设置输出文件路径
	playlistPath := filepath.Join(outputDir, "playlist.m3u8")
	segmentPattern := filepath.Join(outputDir, "segment_%03d.ts")

	// 构建FFmpeg命令
	args := []string{
		"-i", inputPath,
		"-c:v", "libx264",
		"-c:a", "aac",
		"-hls_time", strconv.Itoa(s.SegmentDuration),
		"-hls_list_size", strconv.Itoa(s.MaxSegments),
		"-hls_segment_filename", segmentPattern,
	}

	// 添加自定义选项
	if quality, ok := options["quality"]; ok {
		switch quality {
		case "high":
			args = append(args, "-b:v", "2000k", "-b:a", "128k")
		case "medium":
			args = append(args, "-b:v", "1000k", "-b:a", "96k")
		case "low":
			args = append(args, "-b:v", "500k", "-b:a", "64k")
		}
	}

	// 添加分辨率设置
	if resolution, ok := options["resolution"]; ok {
		args = append(args, "-s", resolution.(string))
	}

	// 添加输出格式和文件
	args = append(args, "-f", "hls", playlistPath)

	// 执行FFmpeg命令
	cmd := exec.Command("ffmpeg", args...)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("FFmpeg转换失败: %v", err)
	}

	return nil
}

// GetVideoInfo 获取视频信息
func (s *HLSService) GetVideoInfo(videoID string) (*VideoInfo, error) {
	videoDir := filepath.Join(s.OutputDir, videoID)
	playlistPath := filepath.Join(videoDir, "playlist.m3u8")

	// 检查播放列表是否存在
	if _, err := os.Stat(playlistPath); os.IsNotExist(err) {
		return nil, fmt.Errorf("视频不存在")
	}

	// 获取目录信息
	dirInfo, err := os.Stat(videoDir)
	if err != nil {
		return nil, fmt.Errorf("获取视频信息失败: %v", err)
	}

	// 计算总大小
	var totalSize int64
	filepath.Walk(videoDir, func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() {
			totalSize += info.Size()
		}
		return nil
	})

	// 读取播放列表获取时长信息
	duration, err := s.getVideoDuration(playlistPath)
	if err != nil {
		duration = 0
	}

	return &VideoInfo{
		ID:          videoID,
		Title:       videoID, // 可以从数据库获取真实标题
		Duration:    duration,
		Size:        totalSize,
		CreatedAt:   dirInfo.ModTime(),
		PlaylistURL: fmt.Sprintf("/api/hls/%s/playlist.m3u8", videoID),
		Status:      "ready",
	}, nil
}

// getVideoDuration 从M3U8文件获取视频总时长
func (s *HLSService) getVideoDuration(playlistPath string) (float64, error) {
	content, err := os.ReadFile(playlistPath)
	if err != nil {
		return 0, err
	}

	lines := strings.Split(string(content), "\n")
	var totalDuration float64

	for _, line := range lines {
		if strings.HasPrefix(line, "#EXTINF:") {
			// 解析 #EXTINF:10.0, 格式
			parts := strings.Split(line, ":")
			if len(parts) > 1 {
				durationStr := strings.Split(parts[1], ",")[0]
				if duration, err := strconv.ParseFloat(durationStr, 64); err == nil {
					totalDuration += duration
				}
			}
		}
	}

	return totalDuration, nil
}

// GenerateMultiQualityHLS 生成多码率HLS
func (s *HLSService) GenerateMultiQualityHLS(inputPath, videoID string) error {
	outputDir := filepath.Join(s.OutputDir, videoID)
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %v", err)
	}

	// 定义不同质量的配置
	qualities := []struct {
		name         string
		resolution   string
		videoBitrate string
		audioBitrate string
	}{
		{"high", "1920x1080", "2000k", "128k"},
		{"medium", "1280x720", "1000k", "96k"},
		{"low", "854x480", "500k", "64k"},
	}

	// 为每个质量生成HLS
	for _, quality := range qualities {
		qualityDir := filepath.Join(outputDir, quality.name)
		if err := os.MkdirAll(qualityDir, 0755); err != nil {
			continue
		}

		playlistPath := filepath.Join(qualityDir, "playlist.m3u8")
		segmentPattern := filepath.Join(qualityDir, "segment_%03d.ts")

		cmd := exec.Command("ffmpeg",
			"-i", inputPath,
			"-c:v", "libx264",
			"-c:a", "aac",
			"-b:v", quality.videoBitrate,
			"-b:a", quality.audioBitrate,
			"-s", quality.resolution,
			"-hls_time", strconv.Itoa(s.SegmentDuration),
			"-hls_list_size", "0",
			"-hls_segment_filename", segmentPattern,
			"-f", "hls",
			playlistPath,
		)

		if err := cmd.Run(); err != nil {
			fmt.Printf("生成%s质量失败: %v\n", quality.name, err)
			continue
		}
	}

	// 生成主播放列表
	return s.generateMasterPlaylist(videoID, qualities)
}

// generateMasterPlaylist 生成主播放列表
func (s *HLSService) generateMasterPlaylist(videoID string, qualities []struct {
	name         string
	resolution   string
	videoBitrate string
	audioBitrate string
}) error {
	outputDir := filepath.Join(s.OutputDir, videoID)
	masterPlaylistPath := filepath.Join(outputDir, "master.m3u8")

	var content strings.Builder
	content.WriteString("#EXTM3U\n")
	content.WriteString("#EXT-X-VERSION:3\n\n")

	for _, quality := range qualities {
		// 提取比特率数字
		bitrate := strings.TrimSuffix(quality.videoBitrate, "k")

		content.WriteString(fmt.Sprintf("#EXT-X-STREAM-INF:BANDWIDTH=%s000,RESOLUTION=%s\n",
			bitrate, quality.resolution))
		content.WriteString(fmt.Sprintf("%s/playlist.m3u8\n\n", quality.name))
	}

	return os.WriteFile(masterPlaylistPath, []byte(content.String()), 0644)
}

// CleanupOldVideos 清理旧的视频文件
func (s *HLSService) CleanupOldVideos(maxAge time.Duration) error {
	entries, err := os.ReadDir(s.OutputDir)
	if err != nil {
		return err
	}

	now := time.Now()
	for _, entry := range entries {
		if entry.IsDir() {
			info, err := entry.Info()
			if err != nil {
				continue
			}

			if now.Sub(info.ModTime()) > maxAge {
				videoDir := filepath.Join(s.OutputDir, entry.Name())
				if err := os.RemoveAll(videoDir); err != nil {
					fmt.Printf("删除旧视频失败 %s: %v\n", entry.Name(), err)
				} else {
					fmt.Printf("已删除旧视频: %s\n", entry.Name())
				}
			}
		}
	}

	return nil
}
